package com.penghe.www.baselibrary.utils

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.createBitmap
import android.graphics.BitmapFactory.Options
import android.graphics.BitmapFactory.decodeStream
import android.graphics.Canvas
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.support.annotation.DrawableRes
import android.widget.ImageView
import com.penghe.www.baselibrary.R
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream
import java.net.HttpURLConnection
import java.net.URL
import java.util.Collections.synchronizedMap
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors


/**
 * Created by alm on 17-6-1.
 * 图片加载工具
 */

class ImageLoader constructor(context: Context) {

    companion object {
        /**
         * 单例对象
         */
        private var _INSTANCE: ImageLoader? = null

        /**
         * 获取单例
         */
        fun getInstance(context: Context): ImageLoader {
            if (_INSTANCE == null) {
                synchronized(ImageLoader::class) {
                    if (_INSTANCE == null) {
                        _INSTANCE = ImageLoader(context)
                    }
                }
            }
            return _INSTANCE!!
        }
    }

    /**
     * 内存缓存工具类
     */
    private val memoryCache: MemoryCache = MemoryCache()

    /**
     * 文件缓存工具类
     */
    private val fileCache: FileCache = FileCache(context)


    /**
     * 存储图片控件的集合
     */
    private val imageViewList: MutableMap<ImageView, String> = synchronizedMap(java.util.WeakHashMap<ImageView, String>())

    /**
     * 线程池
     */
    private val executorService: ExecutorService = Executors.newFixedThreadPool(10)

    /**
     * 默认显示的图片
     */
    @DrawableRes
    private val defaultDrawable: Int = R.drawable.ic_launcher

    /**
     * 图片边线的宽度(剪切为圆形的时候)
     */
    private val strokeWidth: Int = 0

    /**
     * 是否显示为圆形
     */
    private var mIsCircle: Boolean = false

    /**
     * 是否压缩图片
     */
    private var mCompress: Boolean = false

    /**
     * 图片压缩时，判断图片大小(超过这个大小才压缩)
     */
    private val REQUIRED_SIZE = 70

    //自定义函数

    /**
     * 显示图片
     *
     * @param url 图片的网络地址
     * @param imageView 图片控件
     * @param isCircle 是否显示为圆形
     */
    fun displayImage(url: String, imageView: ImageView, isCircle: Boolean) {
        mIsCircle = isCircle
        imageViewList.put(imageView, url)
        // 先从内存缓存中查找
        val bitmap: Bitmap? = memoryCache.get(url)
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap)
        } else {
            imageView.setImageResource(defaultDrawable)
            // 若没有的话则开启新线程加载图片
            loadBitmapFromNet(url, imageView)
        }
    }

    /**
     * 清除缓存
     */
    fun clearCache() {
        memoryCache.clear()
        fileCache.clear()
    }

    /**
     * 检测图片控件是否重用(防止图片错位)
     *
     * @param bitmapHolder BitmapHolder
     * @return false表示错位
     */
    fun imageViewReused(bitmapHolder: BitmapHolder): Boolean {
        val tag: String? = imageViewList[bitmapHolder.imageView]

        return tag == null || tag != bitmapHolder.url
    }

    /**
     * 下载图片操作
     */
    fun copyStream(inputStream: InputStream, outputStream: OutputStream) {
        val bufferSize: Int = 1024
        val bytes: ByteArray = ByteArray(bufferSize)
        while (true) {
            val count: Int = inputStream.read(bytes, 0, bufferSize)
            if (count == -1) {
                break
            }
            outputStream.write(bytes, 0, count)
        }
    }

    /**
     * 获取图片 先从缓存中去查找，如果没有再从网络下载
     *
     * @param url 图片网络地址
     * @return 图片
     */
    fun getBitmap(url: String): Bitmap {
        val file: File = fileCache.getFile(url)

        // 先从文件缓存中查找是否有
        var bitmap: Bitmap? = decodeFile(file)
        if (bitmap != null) {
            return bitmap
        }

        val imageUrl: URL = URL(url)
        val conn: HttpURLConnection = imageUrl.openConnection() as HttpURLConnection
        conn.connectTimeout = 5000
        conn.readTimeout = 5000
        conn.instanceFollowRedirects = true
        val inputStream: InputStream = conn.inputStream
        val fileOutputStream: FileOutputStream = FileOutputStream(file)
        copyStream(inputStream, fileOutputStream)
        fileOutputStream.flush()
        fileOutputStream.close()
        inputStream.close()
        bitmap = decodeFile(file)
        return bitmap
    }

    /**
     * 设置是否压缩图片
     */
    fun setCompress(compress: Boolean) {
        mCompress = compress
    }

    fun getMemoryCache(): MemoryCache {
        return memoryCache
    }

    @DrawableRes
    fun getDefaultDrawable(): Int {
        return defaultDrawable
    }

    //内部私有函数

    /**
     * 从网络加载图片
     */
    private fun loadBitmapFromNet(url: String, imageView: ImageView) {
        val bitmapHolder: BitmapHolder = BitmapHolder(url, imageView)
        executorService.submit(BitmapLoader(bitmapHolder, this))
    }

    private fun decodeFile(file: File): Bitmap {
        val bitmap: Bitmap
        //压缩图片
        if (mCompress) {
            // 不加载图片的情况下获得图片的宽高
            val options: Options = Options()
            options.inJustDecodeBounds = true
            decodeStream(java.io.FileInputStream(file), null, options)

            var width_tmp = options.outWidth
            var height_tmp = options.outHeight

            //记录压缩倍数
            var scale = 1

            // 如果长或宽大于REQUIRED_SIZE，那么把图片的高宽缩小一半，直到宽高都小于REQUIRED_SIZE后停止压缩
            while (true) {
                if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) {
                    break
                }
                width_tmp /= 2
                height_tmp /= 2
                scale *= 2
            }

            val options1 = Options()
            options1.inSampleSize = scale
            // 把图片的高宽缩小一半
            bitmap = decodeStream(java.io.FileInputStream(file), null, options1)
        } else {
            val options = Options()
            bitmap = decodeStream(java.io.FileInputStream(file), null, options)
        }

        if (mIsCircle) {
            return createCircleBitmap(bitmap)
        } else {
            return bitmap
        }
    }

    /**
     * 把 源图片 加工成 圆形图片
     * @param bitmap 源图片
     */
    private fun createCircleBitmap(bitmap: Bitmap): Bitmap {
        val width = bitmap.width
        val paint = android.graphics.Paint()
        // 画圆或者弧形图，需要抗锯齿
        paint.isAntiAlias = true

        // 创建一张空图片, 这张图片只有宽高，没有内容
        //noinspection SuspiciousNameCombination
        val target = createBitmap(width, width, Bitmap.Config.ARGB_8888)

        val canvas = Canvas(target)

        // 画一个和原图片宽高一样的内切圆
        canvas.drawCircle((width / 2).toFloat(), (width / 2).toFloat(), ((width - strokeWidth) / 2).toFloat(),
                paint)

        // 取两图的交集(也就是重合的部分)
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)

        // 把源图覆盖上去
        canvas.drawBitmap(bitmap, 0f, 0f, paint)

        return target
    }
}